package com.ruoyi.common.utils;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.CollectionUtils;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public class XssUtil {
    private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;


    /**
     * 校验HSSF类型Excel 的xss攻击
     *
     * @param is
     * @return
     * @throws IOException
     */
    public static Boolean checkHSSFExcelXssFlag(FileInputStream is) throws IOException
    {
        HSSFWorkbook wor = new HSSFWorkbook(is);
        HSSFSheet sheet = wor.getSheetAt(0);
        int hs = sheet.getPhysicalNumberOfRows();
        HSSFRow rows = sheet.getRow(1);
        int cellNum = rows.getLastCellNum();
        boolean xssFlag = true;
        for(int j = 1; j < hs && xssFlag; j++)
        {
            HSSFRow row = sheet.getRow(j);
            for(int i = 0; i < cellNum; i++)
            {
                String cellValue = String.valueOf(row.getCell(i));
                // 判断字符是否正常
                //字符正常返回true
                boolean flag = checkXssForExcel(cellValue);
                if(!flag)
                {
                    xssFlag = false;
                    break;
                }
            }
        }
        return xssFlag;
    }

    /**
     * 校验XSSF类型Excel 的xss攻击
     *
     * @param is
     * @return
     * @throws IOException
     */
    public static Boolean checkXSSFExcelXssFlag(FileInputStream is) throws IOException
    {
        XSSFWorkbook wor = new XSSFWorkbook(is);
        XSSFSheet sheet = wor.getSheetAt(0);
        int hs = sheet.getPhysicalNumberOfRows();
        XSSFRow rows = sheet.getRow(1);
        int cellNum = rows.getLastCellNum();
        boolean xssFlag = true;
        for(int j = 1; j < hs && xssFlag; j++)
        {
            XSSFRow row = sheet.getRow(j);
            for(int i = 0; i < cellNum; i++)
            {
                String cellValue = String.valueOf(row.getCell(i));
                // 判断字符是否正常
                //字符正常返回true
                boolean flag = XssUtil.checkXssForExcel(cellValue);
                if(!flag)
                {
                    xssFlag = false;
                    break;
                }
            }
        }
        return xssFlag;
    }

    /**
     * 校验excel中是否包含特殊字符
     *
     * @param val
     * @return
     */
    public static Boolean checkXssForExcel(String val)
    {
        Boolean flag = false;
        String valInit = val;
        List<Pattern> xssTagList = new ArrayList<>();
        xssTagList.add(Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
        xssTagList.add(Pattern.compile("e-xpression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
        xssTagList.add(Pattern.compile("javascript[\r\n| | ]*:[\r\n| |]*", Pattern.CASE_INSENSITIVE));
        xssTagList.add(Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
        xssTagList.add(Pattern.compile("select", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
        xssTagList.add(Pattern.compile("insert", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
        xssTagList.add(Pattern.compile("delete", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
        xssTagList.add(Pattern.compile("update", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
        xssTagList.add(Pattern.compile("and", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
        xssTagList.add(Pattern.compile("or", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
        xssTagList.add(Pattern.compile("count", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
        xssTagList.add(Pattern.compile("chr", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
        xssTagList.add(Pattern.compile("<!--(.*?)-->", Pattern.DOTALL));
        xssTagList.add(Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI));
        xssTagList.add(Pattern.compile("<(.*?)>", Pattern.DOTALL));
//        xssTagList.add(Pattern.compile("^([^:]+):", REGEX_FLAGS_SI));
        xssTagList.add(Pattern.compile("&([^&;]*)(?=(;|&|$))"));
        xssTagList.add(Pattern.compile("^>"));
        xssTagList.add(Pattern.compile("<([^>]*?)(?=<|$)"));
        xssTagList.add(Pattern.compile("(^|>)([^<]*?)(?=>)"));
        xssTagList.add(Pattern.compile("<([^>]*?)(?=<|$)"));
        xssTagList.add(Pattern.compile("(^|>)([^<]*?)(?=>)"));
        xssTagList.add(Pattern.compile("&"));
        xssTagList.add(Pattern.compile("\""));
        xssTagList.add(Pattern.compile("<"));
        xssTagList.add(Pattern.compile(">"));
        xssTagList.add(Pattern.compile("<>"));

        if(!CollectionUtils.isEmpty(xssTagList))
        {
            for(Pattern pattern : xssTagList)
            {
                val = pattern.matcher(val).replaceAll("");
            }
        }

        if(val.equals(valInit))
        {
            flag = true;
        }
        return flag;
    }
}
